import CryptoJS from "crypto-js";
// interface Item {
//   [key: string]: string;
// }

class Crypto {
  constructor() {}
  /**
   * @description 判断是否经过base64加密
   * @param data 传递的参数
   * @returns 返回 boolean
   */
  private isBase64(data: string): boolean {
    try {
      return btoa(atob(data)) === data;
    } catch (err) {
      console.warn(err);
      return false;
    }
  }
  public md5Encrypto(data: string) {
    const encrypto = CryptoJS.MD5(data).toString();
    return encrypto;
  }
  public Sign(str: string) {
    return this.md5Encrypto(str).toUpperCase().substring(10, 18);
  }

  public base64Encrypt(data: string) {
    if (!data || data === JSON.stringify([""])) return "";
    const encodedString = CryptoJS.enc.Utf8.parse(data).toString(
      CryptoJS.enc.Base64
    );
    return encodedString;
  }

  /**
   * @description Base64解密
   * @param data 传递解密参数
   * @param type 解密类型
   * @returns 返回解密数据
   */

  // 重载签名 1: 参数为字符串，返回字符串
  public base64Decrypt(data: string): string;

  // 重载签名 2: 参数为数组，返回数组
  public base64Decrypt(
    data: Array<Record<string, string>>,
    type: "Array"
  ): Array<Record<string, string>>;

  // 重载签名 3: 参数为对象，返回对象
  public base64Decrypt(
    data: Record<string, string>,
    type: "Object"
  ): Record<string, string>;

  public base64Decrypt(
    data: string | Array<Record<string, string>> | Record<string, string>,
    type?: "Array" | "Object"
  ): string | Array<Record<string, string>> | Record<string, string> {
    //判断字符串
    if (typeof data == "string") {
      if (!data) return "";
      if (!this.isBase64(data)) {
        console.warn("传进来的值没有进行加密");
        return data;
      }
      return CryptoJS.enc.Base64.parse(data).toString(CryptoJS.enc.Utf8);
    } else if (type == "Array" && Array.isArray(data)) {
      //判断数组
      if (data.length == 0) return [];

      const result = data.map((item) => {
        return Object.keys(item).reduce(
          (arr, key) => {
            arr[key] = item[key]
              ? CryptoJS.enc.Base64.parse(item[key]).toString(CryptoJS.enc.Utf8)
              : "";
            return arr;
          },
          {} as Record<string, string>
        );
      });

      return result;

      // return this.decryptArray(data);
    } else if (
      type == "Object" &&
      Object.prototype.toString.call(data) === "[object Object]"
    ) {
      //判断对象
      if (Object.keys(data).length == 0) return {};

      const result: Record<string, string> = {};
      for (const key in data) {
        if (Object.prototype.hasOwnProperty.call(data, key)) {
          const value = (data as Record<string, string>)[key];
          result[key] = value
            ? CryptoJS.enc.Base64.parse(value).toString(CryptoJS.enc.Utf8)
            : "";
        }
      }
      return result;
    } else {
      throw new Error("Invalid type provided.");
    }
  }

  public decryptArray<T>(data: []): T[] {
    return this.base64Decrypt(data, "Array") as unknown as T[];
  }

  private decryptString(data: string) {
    if (!data) return "";
    if (!this.isBase64(data)) {
      console.warn("传进来的值没有进行加密");
      return data;
    }
    return CryptoJS.enc.Base64.parse(data).toString(CryptoJS.enc.Utf8);
  }

  // private decryptArray(data: Array<{ [key: string]: string }>): Array<object> {
  //   if (data.length == 0) return [];

  //   const result = data.map((item) => {
  //     return Object.keys(item).reduce(
  //       (arr, key) => {
  //         arr[key] = item[key]
  //           ? CryptoJS.enc.Base64.parse(item[key] as string).toString(
  //               CryptoJS.enc.Utf8
  //             )
  //           : "";
  //         return arr;
  //       },
  //       {} as Record<string, string>
  //     );
  //   });

  //   return result;
  // }

  private decryptObject(data: { [key: string]: string }): object {
    if (Object.keys(data).length == 0) return {};
    const result: Record<string, string> = {};
    for (const key in data) {
      result[key] = data[key]
        ? CryptoJS.enc.Base64.parse(data[key] as string).toString(
            CryptoJS.enc.Utf8
          )
        : "";
    }
    return result;
  }
}

const crypto = new Crypto();

export default crypto;
